package org.cloud.core.common.jwt;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jwt.proc.BadJWTException;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @author Violet
 * @description JWT生成和校验工具类
 * @date 2021/5/20
 */
@Component("weedJwt")
public class WeedJwt {

    private final String SECRET = "297a1a7dcaa4a585c7be0e43bcd160742b0a999f";
    public static final String TOKEN_PREFIX = "bearer ";

    /**
     * 通过HMAC算法生成token
     *
     * @param weedPayload 载荷
     * @return token
     */
    public String generateToken(WeedPayload weedPayload) throws JsonProcessingException, JOSEException {
        if (weedPayload == null) {
            throw new IllegalArgumentException("jwt payload could not be null");
        }
        JWSHeader jwsHeader = new JWSHeader
                .Builder(JWSAlgorithm.HS256)
                .type(JOSEObjectType.JWT)
                .build();
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(weedPayload);
        Payload payload = new Payload(json);
        JWSObject jwsObject = new JWSObject(jwsHeader, payload);
        JWSSigner jwsSigner = new MACSigner(this.SECRET);
        jwsObject.sign(jwsSigner);
        String token = jwsObject.serialize();
        return TOKEN_PREFIX + token;
    }

    /**
     * token解密
     *
     * @param token token
     * @return 载荷
     */
    public WeedPayload verifyToken(String token) throws Exception {
        if (StrUtil.isEmpty(token) || !token.startsWith(TOKEN_PREFIX)) {
            throw new BadJWTException("token is empty or illegal");
        }

        token = token.replace(TOKEN_PREFIX, "").trim();

        JWSObject jwsObject = JWSObject.parse(token);
        MACVerifier verifier = new MACVerifier(this.SECRET);
        if (!jwsObject.verify(verifier)) {
            throw new BadJWTException("token is illegal");
        }

        String payload = jwsObject.getPayload().toString();
        ObjectMapper objectMapper = new ObjectMapper();
        WeedPayload weedPayload = objectMapper.readValue(payload, WeedPayload.class);
        if (weedPayload.getExp() < new Date().getTime()) {
            throw new BadJWTException("token has expired");
        }
        return weedPayload;
    }

    /**
     * 获取用户id的快捷方式
     *
     * @param token token
     * @return 用户id
     * @throws Exception exception
     */
    public Long getUserId(String token) throws Exception {
        WeedPayload weedPayload = this.verifyToken(token);
        return weedPayload.getUserId();
    }
}
